#include "StdAfx.h"
#include "ImageListEx.h"

#define KEY_COLOR Color(255, 0, 255)

#define ALPHA_MATRIX(alpha)		\
		{ 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,		\
		  0.0f, 1.0f, 0.0f, 0.0f, 0.0f,		\
		  0.0f, 0.0f, 1.0f, 0.0f, 0.0f,		\
		  0.0f, 0.0f, 0.0f, alpha, 0.0f,	\
		  0.0f, 0.0f, 0.0f, 0.0f, 1.0f}	

#define INVERT_COLOR_MATRIX	\
		{-1.0f, 0.0f, 0.0f, 0.0f, 0.0f,		\
		  0.0f, -1.0f, 0.0f, 0.0f, 0.0f,	\
		  0.0f, 0.0f, -1.0f, 0.0f, 0.0f,	\
		  0.0f, 0.0f, 0.0f, 1.0f, 0.0f,		\
		  1.0f, 1.0f, 1.0f, 0.0f, 1.0f}	

#define INVERT_ALPHA_MATRIX(alpha)	\
		{-1.0f, 0.0f, 0.0f, 0.0f, 0.0f,		\
		  0.0f, -1.0f, 0.0f, 0.0f, 0.0f,	\
		  0.0f, 0.0f, -1.0f, 0.0f, 0.0f,	\
		  0.0f, 0.0f, 0.0f, alpha, 0.0f,	\
		  1.0f, 1.0f, 1.0f, 0.0f, 1.0f}	

CImageListEx::CImageListEx(void)
{
	_pBitmap = NULL;

	_imageHeight = NULL;
	_imageWidth = NULL;

	_nImageCount = 0;
	_bManaged = FALSE;
}

CImageListEx::~CImageListEx(void)
{
	_disposeBitmap(_bManaged);
}

int CImageListEx::Attach(Gdiplus::Bitmap* pBitmap, int nIconCount, bool bManaged)
{
	if(!pBitmap) return -1;

	_disposeBitmap(_bManaged);
	
	_pBitmap = pBitmap;

	_imageHeight = _pBitmap->GetHeight();
	_imageWidth = _pBitmap->GetWidth()/nIconCount;
	_nImageCount = nIconCount;

	_bManaged = bManaged;

	return 0;
}

void CImageListEx::Detach()
{
	_disposeBitmap(_bManaged);
}

int CImageListEx::Load(HINSTANCE hInst, int resID, int nImageCount
						, LPCWSTR pszResType)
{
	_disposeBitmap(_bManaged);

	// Make sure GDIPlus already initialized!
	if(pszResType == RT_BITMAP)
	{
		_pBitmap = new Gdiplus::Bitmap(hInst, MAKEINTRESOURCE(resID));
	}
	else
	{
		CreateBitmapFromPNG(hInst, resID, pszResType, _pBitmap);
	}
	ATLASSERT(_pBitmap);
	
	if(!_pBitmap) return -1;

	_imageHeight = _pBitmap->GetHeight();
	_imageWidth = _pBitmap->GetWidth()/nImageCount;
	_nImageCount = nImageCount;
	_bManaged = TRUE;

	return 0;
}

int CImageListEx::Load(LPCWSTR pszFileName, int nImageCount)
{
	_disposeBitmap(_bManaged);
	_pBitmap = new Gdiplus::Bitmap(pszFileName);

	ATLASSERT(_pBitmap);

	if(!_pBitmap) return -1;

	_imageHeight = _pBitmap->GetHeight();
	_imageWidth = _pBitmap->GetWidth()/nImageCount;
	_nImageCount = nImageCount;
	_bManaged = TRUE;

	return 0;
}

int CImageListEx::Load(HBITMAP hBitmap, int nImageCount)
{
	_disposeBitmap(_bManaged);

	_pBitmap = new Gdiplus::Bitmap(hBitmap, 0);

	if(!_pBitmap) return -1;

	_imageHeight = _pBitmap->GetHeight();
	_imageWidth = _pBitmap->GetWidth()/nImageCount;

	_nImageCount = nImageCount;
	_bManaged = TRUE;

	return 0;
}

int CImageListEx::Destroy()
{
	_disposeBitmap(_bManaged);
	return 0;
}

int CImageListEx::StrechDraw(HDC dc, int nImage
							, int destx, int desty, int destWidth, int destHeight
							, DWORD drawStyle, float alpha, int nAdjustWidth)
{
	ATLASSERT(_pBitmap);

	Gdiplus::Graphics graphics(dc);

	int ret = 0;
	int srcx = nImage * _imageWidth;

	Gdiplus::Rect destRect(destx, desty, destWidth, destHeight);
	if(drawStyle == DS_NORMAL)
	{
		return graphics.DrawImage( _pBitmap, destRect, srcx, 0
			, _imageWidth + nAdjustWidth, _imageHeight, Gdiplus::UnitPixel);
	}
	else
	{
		return _drawImageWithStyle(graphics, destx, desty, destRect, srcx, drawStyle, alpha);
	}
}

int CImageListEx::Draw(HDC dc, int nImage, int destx, int desty
						, DWORD drawStyle, float alpha)
{
	ATLASSERT(_pBitmap);

	Gdiplus::Graphics graphics(dc);

	int ret = 0;
	int srcx = nImage * _imageWidth;

	if(drawStyle == DS_NORMAL)
	{
		return graphics.DrawImage( _pBitmap, destx, desty, srcx, 0
								, _imageWidth, _imageHeight, Gdiplus::UnitPixel);
	}
	else
	{
		Gdiplus::Rect destRect(destx, desty, _imageWidth, _imageHeight);
		return _drawImageWithStyle(graphics, destx, desty, destRect
									, srcx, drawStyle, alpha);
	}
}

int CImageListEx::_drawImageWithStyle(Gdiplus::Graphics& graphics
									, int x, int y, Gdiplus::Rect& destRect, int srcx
									, DWORD drawStyle, float alpha)
{
	Gdiplus::ImageAttributes imageAttributes;

	if(drawStyle & DS_KEYCOLOR)
	{
		imageAttributes.SetColorKey( Gdiplus::KEY_COLOR, Gdiplus::KEY_COLOR, Gdiplus::ColorAdjustTypeBitmap);   
	}

	//ColorMatrix colorMatrix;
	if((drawStyle & DS_INVERT) && !(drawStyle & DS_ALPHA))
	{
		Gdiplus::ColorMatrix colorMatrix = INVERT_COLOR_MATRIX;
		imageAttributes.SetColorMatrix(&colorMatrix, Gdiplus::ColorMatrixFlagsDefault
			, Gdiplus::ColorAdjustTypeBitmap);
	}
	if((drawStyle & DS_ALPHA) && !(drawStyle & DS_INVERT))
	{
		Gdiplus::ColorMatrix colorMatrix = ALPHA_MATRIX(alpha);
		imageAttributes.SetColorMatrix(&colorMatrix, Gdiplus::ColorMatrixFlagsDefault
			, Gdiplus::ColorAdjustTypeBitmap);
	}
	if((drawStyle & DS_ALPHA) && (drawStyle & DS_INVERT))
	{
		Gdiplus::ColorMatrix colorMatrix = INVERT_ALPHA_MATRIX(alpha);
		imageAttributes.SetColorMatrix(&colorMatrix, Gdiplus::ColorMatrixFlagsDefault
			, Gdiplus::ColorAdjustTypeBitmap);
	}

	return graphics.DrawImage( _pBitmap, destRect, srcx, 0
							, _imageWidth, _imageHeight
							, Gdiplus::UnitPixel, &imageAttributes );
}

bool CImageListEx::GetImageSize(int& width, int& height)
{
	ATLASSERT(_imageWidth | !_pBitmap);
	ATLASSERT(_imageHeight | !_pBitmap);

	width = _imageWidth;
	height = _imageHeight;
	return TRUE;
}

int CImageListEx::GetImageCount()
{
	ATLASSERT(_nImageCount | !_pBitmap);
	return _nImageCount;
}

Gdiplus::Bitmap* CImageListEx::GetBitmap()
{
	return _pBitmap;
}

bool CImageListEx::CreateBitmapFromPNG(HINSTANCE hInst, UINT nID
										, LPCTSTR pszResType, Gdiplus::Bitmap*& pBitmap)
{
	HRSRC hRsrc = ::FindResource (hInst, MAKEINTRESOURCE(nID), pszResType); // type
	if (!hRsrc)
		return FALSE;

	// load resource into memory
	DWORD len = SizeofResource(hInst, hRsrc);
	BYTE* lpRsrc = (BYTE*)LoadResource(hInst, hRsrc);
	if (!lpRsrc)
		return FALSE;

	// Allocate global memory on which to create stream
	HGLOBAL m_hMem = GlobalAlloc(GMEM_FIXED, len);
	BYTE* pmem = (BYTE*)GlobalLock(m_hMem);
	memcpy(pmem, lpRsrc, len);
	IStream* pstm;
	CreateStreamOnHGlobal(m_hMem, TRUE, &pstm);

	// load from stream
	pBitmap = Gdiplus::Bitmap::FromStream(pstm);

	// free/release stuff
	GlobalUnlock(m_hMem);
	pstm->Release();
	FreeResource(lpRsrc);

	return TRUE;
}

void CImageListEx::_disposeBitmap(bool bManaged)
{
	if(_pBitmap && !bManaged)
	{
		delete _pBitmap;
	}

	_pBitmap = NULL;

	_imageWidth = 0;
	_imageHeight = 0;

	_nImageCount = 0;
}
